using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Web.UI;

namespace ModWatch
{

	/// <summary>
	/// Provides a base implementation for <see cref="ModWatch.ModWatchExtenderBase"/>
	/// controls that track changes to <see cref="ModWatch.IModWatcher"/> objects.
	/// </summary>
	public abstract class ModAlertExtenderBase : ModWatchExtenderBase
	{

		#region Properties

		/// <summary>
		/// Gets or sets the modification group to be checked for changes.
		/// </summary>
		[DefaultValue("")]
		public string ModGroup
		{
			get { return GetProperty("ModGroup", ""); }
			set { SetProperty("ModGroup", value); }
		}

		/// <summary>
		/// Gets or sets the ID of the <see cref="AlertBehaviorBase"/> control that defines
		/// how the user should be notified if a change has occurred.
		/// </summary>
		[DefaultValue("")]
		public string AlertBehaviorID
		{
			get { return GetProperty("AlertBehaviorID", ""); }
			set { SetProperty("AlertBehaviorID", value); }
		}

		private AlertBehaviorBase _alertBehavior;
		/// <summary>
		/// Gets or sets the <see cref="AlertBehaviorBase"/> control that defines
		/// how the user should be notified if a change has occurred.
		/// </summary>
		public AlertBehaviorBase AlertBehavior
		{
			get { return _alertBehavior; }
			set { _alertBehavior = value; }
		}

		/// <summary>
		/// Gets or sets the dialog message that should prompt the user if a change exists.
		/// If an Alert Control is specified through either the AlertControlID or
		/// AlertControl properties, then this property is not used.
		/// </summary>
		[DefaultValue("")]
		public string NotifyModMessage
		{
			get { return GetProperty("NotifyModMessage", ""); }
			set { SetProperty("NotifyModMessage", value); }
		}

		#endregion

		#region Events

		/// <summary>
		/// Raises the <see cref="System.Web.UI.Control.Init"/> event.
		/// </summary>
		/// <param name="e">
		/// An <see cref="System.EventArgs"/>
		/// object that contains event data.
		/// </param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);

			this.GettingScriptReferences += new EventHandler<ScriptReferencesEventArgs>(this_GettingScriptReferences);
		}

		/// <summary>
		/// Registers the scripts needed by the
		/// <see cref="ModWatch.ModAlertExtenderBase"/> class.
		/// </summary>
		/// <param name="sender">
		/// The <see cref="System.Object"/> that fired the
		/// <see cref="ModWatch.ModWatchExtenderBase.GettingScriptReferences"/> event.
		/// </param>
		/// <param name="e">
		/// A <see cref="ModWatch.ScriptReferencesEventArgs"/> object that contains the event data.
		/// </param>
		private void this_GettingScriptReferences(object sender, ScriptReferencesEventArgs e)
		{
			e.AddWebResourceScriptReference("ModWatch.Scripts.IModWatcher.js");
			e.AddWebResourceScriptReference("ModWatch.Scripts.ModAlertBehaviorBase.js");
			e.AddWebResourceScriptReference("ModWatch.Scripts.ModManager.js");
		}

		#endregion

		#region Protected Methods

		/// <summary>
		/// Returns the <see cref="AlertBehaviorBase"/> implementation that
		/// should be used to notify the user of a change.
		/// </summary>
		/// <returns></returns>
		protected AlertBehaviorBase GetAlertBehaviorBase()
		{
			if (AlertBehaviorID.Length == 0)
				return AlertBehavior;

			Control locatedControl = FindControl(this, AlertBehaviorID);
			if (locatedControl == null)
				throw new ModWatchException(String.Format("A control with id '{0}' could not be found.", AlertBehaviorID));

			AlertBehaviorBase alert = locatedControl as AlertBehaviorBase;
			if (alert == null)
				throw new ModWatchException(String.Format("The control with id '{0}' does not implement AlertBehaviorBase.", AlertBehaviorID));

			return alert;
		}

		/// <summary>
		/// Locates the control with the indicated id.  If the control
		/// is not found in the current Naming Container, then each parent
		/// Naming Container is searched until the control is found.
		/// </summary>
		/// <param name="control">
		/// The control indicating the Naming Container
		/// in which the searching should begin.
		/// </param>
		/// <param name="controlID">
		/// The id of the control to be located.
		/// </param>
		/// <returns>The control with the indicated id.</returns>
		private Control FindControl(Control control, string controlID)
		{
			if (control == control.Page)
				return control.FindControl(controlID);

			Control namingContainer = control;
			Control locatedControl = null;

			while (locatedControl == null && namingContainer != control.Page)
			{
				namingContainer = namingContainer.NamingContainer;
				if (namingContainer == null)
				{
					throw new ModWatchException("Naming container was not found.");
				}
				locatedControl = namingContainer.FindControl(controlID);
			}
			return locatedControl;
		}

		#endregion

	}

}
